package com.harmontronics.hanma.paas.paas.domain.app.repository.persistence;

import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.Maps;
import com.harmontronics.hanma.paas.paas.consts.DbConstants;
import com.harmontronics.hanma.paas.paas.domain.app.entity.valueobject.EntityModelStatusEnum;
import com.harmontronics.hanma.paas.paas.domain.app.entity.valueobject.EntityModelTypeEnum;
import com.harmontronics.hanma.paas.paas.domain.app.entity.valueobject.Fields;
import com.harmontronics.hanma.paas.paas.domain.app.repository.mapper.HmEntityModelMapper;
import com.harmontronics.hanma.paas.paas.domain.app.repository.po.HmEntityModelPO;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.springframework.stereotype.Repository;


/**
 * @author ldb
 */
@Repository("hmEntityModelRepository")
public class HmEntityModelRepository extends ServiceImpl<HmEntityModelMapper, HmEntityModelPO> {
    private static final String DROP_COLUMN_TEMPLATE = "ALTER TABLE \"hm_model_%s\" drop COLUMN if exists %s;";
    private static final String ALTER_COLUMN_TEMPLATE = "ALTER TABLE \"hm_model_%s\" ALTER COLUMN %s;";
    private static final String ADD_COLUMN_TEMPLATE = "alter table \"hm_model_%s\"\n" +
            "            add column %s;";
    public static List<String> MODEL_BUILT_IN_CODES = new ArrayList<>();

    static {
        MODEL_BUILT_IN_CODES.add("id");
        MODEL_BUILT_IN_CODES.add("create_by");
        MODEL_BUILT_IN_CODES.add("create_date");
        MODEL_BUILT_IN_CODES.add("modify_by");
        MODEL_BUILT_IN_CODES.add("modify_date");
        MODEL_BUILT_IN_CODES.add("deleted");
        MODEL_BUILT_IN_CODES.add("process_id");
        MODEL_BUILT_IN_CODES.add("process_instance_id");
        MODEL_BUILT_IN_CODES.add("parent_id");
        MODEL_BUILT_IN_CODES.add("parent_ids");
        MODEL_BUILT_IN_CODES.add("children");
    }

    public IPage<HmEntityModelPO> selectPage(QueryWrapper<HmEntityModelPO> queryWrapper, Page<HmEntityModelPO> page) {
        return baseMapper.selectPage(page, queryWrapper);
    }


    public HmEntityModelPO findByCodeAndModelId(String code, Long modelId) {
        QueryWrapper<HmEntityModelPO> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq(Fields.CODE, code);
        queryWrapper.eq(Fields.MODEL_ID, modelId);
        return baseMapper.selectOne(queryWrapper);
    }


    public List<HmEntityModelPO> findBuiltIn(Long modelId) {
        QueryWrapper<HmEntityModelPO> queryWrapper = new QueryWrapper<>();
        queryWrapper.in(Fields.CODE, MODEL_BUILT_IN_CODES);
        queryWrapper.eq(Fields.MODEL_ID, modelId);
        return baseMapper.selectList(queryWrapper);
    }

    public List<HmEntityModelPO> findScript(Long modelId) {
        QueryWrapper<HmEntityModelPO> queryWrapper = new QueryWrapper<>();
        queryWrapper.in(Fields.STATUS, EntityModelStatusEnum.SCRIPT);
        queryWrapper.eq(Fields.MODEL_ID, modelId);
        return baseMapper.selectList(queryWrapper);
    }


    public List<HmEntityModelPO> findByModelId(Long modelId) {
        QueryWrapper<HmEntityModelPO> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq(Fields.MODEL_ID, modelId);
        return baseMapper.selectList(queryWrapper);
    }


    public List<HmEntityModelPO> findSubTableColumns(Long modelId) {
        QueryWrapper<HmEntityModelPO> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq(Fields.MODEL_ID, modelId);
        queryWrapper.eq(Fields.TYPE_DB, EntityModelTypeEnum.SUB_TABLE.toString());
        return baseMapper.selectList(queryWrapper);
    }

    public List<HmEntityModelPO> findByModelIdAndType(Long modelId,String... types) {
        QueryWrapper<HmEntityModelPO> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq(Fields.MODEL_ID, modelId);
        queryWrapper.in(Fields.TYPE_DB, types);
        queryWrapper.orderByAsc(DbConstants.CREATE_DATE);
        return baseMapper.selectList(queryWrapper);
    }

    /**
     * 查询模型字段实体，并基于code构建为map
     * @param modelId
     * @param types
     * @return
     */
    public Map<String,HmEntityModelPO> findEntityModelsMapByModelIdAndType(Long modelId,String... types) {
        List<HmEntityModelPO> relationSelectEntityModels = findByModelIdAndType(modelId,types);
        // 构建 map，方便后期快速根据 code 查找
        Map<String, HmEntityModelPO> relationSelectEntityModelMap = Maps.newHashMap();
        if(CollectionUtil.isNotEmpty(relationSelectEntityModels)){
            relationSelectEntityModels.forEach(item->{
                relationSelectEntityModelMap.put(item.getCode(),item);
            });
        }
        return relationSelectEntityModelMap;
    }


    public HmEntityModelPO findByNameAndModelId(String name, Long modelId) {
        QueryWrapper<HmEntityModelPO> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq(Fields.NAME, name);
        queryWrapper.eq(Fields.MODEL_ID, modelId);
        return baseMapper.selectOne(queryWrapper);
    }

    /**
     * @param tableName 模型的Code
     * @param columnDef 列定义 如 user_name varchar(255) not null 具体参考{@link com.harmontronics.hanma.paas.paas.domain.app.entity.valueobject.EntityModelTypeEnum}
     */
    public String addColumn(String tableName, String columnDef) {
        baseMapper.addColumn(tableName, columnDef);
        return String.format(ADD_COLUMN_TEMPLATE, tableName, columnDef);
    }

    /**
     * 去除非空约束
     *
     * @param tableName
     * @param columnName
     */
    public void dropNotNull(String tableName, String columnName) {
        baseMapper.alterColumn(tableName, columnName + "drop not null");
    }

    /**
     * 添加非空约束
     *
     * @param tableName
     * @param columnName
     */
    public void setNotNull(String tableName, String columnName) {
        baseMapper.alterColumn(tableName, columnName + "set not null");
    }


    /**
     * 设置varchar长度
     *
     * @param tableName
     * @param columnName
     * @param length
     */
    public String setVarLength(String tableName, String columnName, int length) {
        baseMapper.alterColumn(tableName, columnName + " type character varying(" + length + ")");
        return String.format(ALTER_COLUMN_TEMPLATE, tableName, columnName + " type character varying(" + length + ")");
    }

    /**
     * 删除字段
     *
     * @param tableName
     * @param columnName
     */
    public String dropColumn(String tableName, String columnName) {
        baseMapper.dropColumn(tableName, columnName);
        return String.format(DROP_COLUMN_TEMPLATE, tableName, columnName);
    }
}